package com.jorado.ognl;

import com.jorado.ognl.exception.OgnlException;
import com.jorado.ognl.utils.ClassLoader;
import com.jorado.ognl.utils.MetaUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @Auther: len.zhang
 * @Date: 2019/8/14 14:34
 * @Description:
 */
public class Label {

    private static final Logger LOGGER = LoggerFactory.getLogger(Label.class);

    /**
     * 标签前缀映射
     */
    private static final Map<String, String> LABEL_MAPPER = new ConcurrentHashMap<>(200);

    static {
        LABEL_MAPPER.put("T.", "#");
        LABEL_MAPPER.put("F.", getFuncLabelValue(Func.class));
        LABEL_MAPPER.put("Math.", getFuncLabelValue(Math.class));
        LABEL_MAPPER.put("String.", getFuncLabelValue(String.class));
        LABEL_MAPPER.put("Boolean.", getFuncLabelValue(Boolean.class));
        LABEL_MAPPER.put("Character.", getFuncLabelValue(Character.class));
        LABEL_MAPPER.put("Byte.", getFuncLabelValue(Byte.class));
        LABEL_MAPPER.put("Short.", getFuncLabelValue(Short.class));
        LABEL_MAPPER.put("Integer.", getFuncLabelValue(Integer.class));
        LABEL_MAPPER.put("Long.", getFuncLabelValue(Long.class));
        LABEL_MAPPER.put("Float.", getFuncLabelValue(Float.class));
        LABEL_MAPPER.put("Double.", getFuncLabelValue(Double.class));
        LABEL_MAPPER.put("Thread.", getFuncLabelValue(Thread.class));
        LABEL_MAPPER.put("Runtime.", getFuncLabelValue(Runtime.class));
        LABEL_MAPPER.put("System.", getFuncLabelValue(System.class));
        LABEL_MAPPER.put("Enum.", getFuncLabelValue(Enum.class));
        LABEL_MAPPER.put("UUID.", getFuncLabelValue(UUID.class));
        LABEL_MAPPER.put("ThreadLocalRandom.", getFuncLabelValue(ThreadLocalRandom.class));
        LABEL_MAPPER.put("Cast.", getFuncLabelValue(Converter.class));
        LABEL_MAPPER.put("Convert.", getFuncLabelValue(Converter.class));
        LABEL_MAPPER.put("Time.", getFuncLabelValue(LocalTime.class));
        LABEL_MAPPER.put("Date.", getFuncLabelValue(LocalDate.class));
        LABEL_MAPPER.put("DateTime.", getFuncLabelValue(LocalDateTime.class));
        LABEL_MAPPER.put("LocalTime.", getFuncLabelValue(LocalTime.class));
        LABEL_MAPPER.put("LocalDate.", getFuncLabelValue(LocalDate.class));
        LABEL_MAPPER.put("LocalDateTime.", getFuncLabelValue(LocalDateTime.class));
        LABEL_MAPPER.put("Clock.", getFuncLabelValue(Clock.class));
        LABEL_MAPPER.put("Period.", getFuncLabelValue(Period.class));
        LABEL_MAPPER.put("Instant.", getFuncLabelValue(Instant.class));
        LABEL_MAPPER.put("Duration.", getFuncLabelValue(Duration.class));
        LABEL_MAPPER.put("YearMonth.", getFuncLabelValue(YearMonth.class));
        LABEL_MAPPER.put("Year.", getFuncLabelValue(Year.class));
        LABEL_MAPPER.put("DateTimeFormatter.", getFuncLabelValue(DateTimeFormatter.class));
    }

    /**
     * 注册标签
     *
     * @param label
     * @param cls
     */
    public static synchronized void register(String label, Class cls) {
        if (LABEL_MAPPER.get(label) != null) {
            throw new OgnlException("label [%s] already exist.", label);
        }
        LABEL_MAPPER.put(label + ".", getFuncLabelValue(cls));
        LOGGER.info("register ognl label [{}->{}]", label, cls.getName());
    }

    /**
     * 注册指定的类，label名为类名
     *
     * @param cls
     */
    public static void register(Class cls) {
        register(cls.getSimpleName(), cls);
    }

    /**
     * 通过扫描配置了@OgnlLabel的类注册
     *
     * @param packages
     */
    public static void register(String... packages) {
        for (String pkg : packages) {
            Set<Class<?>> classes = ClassLoader.getClasses(pkg);
            classes.forEach(n -> {
                try {
                    OgnlLabel ognlLabel = MetaUtils.getAnnotation(n, OgnlLabel.class);
                    if (ognlLabel != null && ognlLabel.enabled()) {
                        if (Func.isBlank(ognlLabel.value())) {
                            register(n);
                        } else {
                            register(ognlLabel.value(), n);
                        }
                    }
                } catch (Exception ex) {
                    LOGGER.error("register label error," + ex.getMessage(), ex);
                }
            });
        }
    }

    /**
     * 绑定标签
     *
     * @param label
     * @param cls
     */
    public static synchronized void bind(String label, Class cls) {
        register(label, cls);
    }

    /**
     * 绑定指定的类，label名为类名
     *
     * @param cls
     */
    public static void bind(Class cls) {
        register(cls);
    }

    /**
     * 通过扫描配置了@OgnlLabel的类绑定
     *
     * @param packages
     */
    public static void bind(String... packages) {
        register(packages);
    }

    /**
     * 获取所有标签
     *
     * @return
     */
    public static Map<String, String> getLabelMapper() {
        return LABEL_MAPPER;
    }

    public static void print() {
        LABEL_MAPPER.forEach((k, v) -> System.out.println(k + "->" + v));
    }

    private static String getFuncLabelValue(Class cls) {
        return String.format("@%s@", cls.getName());
    }
}
